use std::time::Duration;

use crate::core::passwd::TeacherOrStudent;
use anyhow::{Result, anyhow};
use jsonwebtoken::{DecodingKey, EncodingKey, Header, Validation, decode, encode};
use time::UtcDateTime;

#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub(crate) struct Claims {
    sub: u32,
    flag: TeacherOrStudent,
    exp: i64,
}
impl Claims {
    pub fn new(uid: u32, flag: TeacherOrStudent) -> Self {
        let exp = UtcDateTime::now() + Duration::from_secs(60 * 60);
        Self {
            sub: uid,
            flag,
            exp: exp.unix_timestamp(),
        }
    }
}

const KEY: &str = "这是安全密钥，要求是最少32个字节，256位";
pub(crate) fn generate_jwt(claims: &Claims) -> Result<String> {
    let header = Header::new(jsonwebtoken::Algorithm::HS256);
    encode(&header, claims, &EncodingKey::from_secret(KEY.as_bytes())).map_err(|e| anyhow!("{e}"))
}

pub(crate) fn validate_jwt(token: impl AsRef<str>) -> Result<Claims> {
    let decoded = decode::<Claims>(
        token.as_ref(),
        &DecodingKey::from_secret(KEY.as_bytes()),
        &Validation::new(jsonwebtoken::Algorithm::HS256),
    )
    .map_err(|e| anyhow!("{e}"))?;
    Ok(decoded.claims)
}
